/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.actions; import java.util.ResourceBundle; import java.awt.Dialog; import java.awt.Window; import java.awt.Rectangle; import java.awt.event.*; import java.io.*; import java.util.HashSet; import javax.swing.*; import org.openide.*; import org.openide.loaders.*; import org.openide.cookies.*; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileLock; import org.openide.explorer.propertysheet.*; import org.openide.util.*; import org.openide.util.actions.CookieAction; import org.openide.nodes.*; /** Customize a JavaBean. * Opens a Property Sheet and allows making a * serialized prototype from the modified object. * <p>This class is final only for performance reasons. * * @author Ian Formanek */ public final class CustomizeBeanAction extends CookieAction { /** generated Serialized Version UID */ static final long serialVersionUID = -6378495195905487716L; /* Actually performs this action */ protected void performAction (final Node[] activatedNodes) { // posts the request to request to have free AWT-Event-Queue thread RequestProcessor.postRequest (new Runnable () { public void run () { if (compileNodes (activatedNodes)) { customize ((InstanceCookie)activatedNodes[0].getCookie(InstanceCookie.class)); } } }); } /** Execute some data objects. * * @param nodes the array of nodes to compile * @return true if compilation succeeded or was not performed, false if compilation failed */ public static boolean compileNodes(Node[] nodes) { // search all nodes with unique ExecCookies/StartCookies - // - it is possible, that multiple activated nodes have the same exec cookie and // we have to prevent running it multiple times HashSet compile = new HashSet (); for (int i = 0; i < nodes.length; i++) { CompilerCookie comp = (CompilerCookie) nodes[i].getCookie(CompilerCookie.Compile.class); if (comp != null) { compile.add(comp); } } // compile if (!AbstractCompileAction.compile(java.util.Collections.enumeration(compile), AbstractCompileAction.findName(nodes))) { return false; } return true; } /* Exactly one selected node. */ protected int mode () { return MODE_EXACTLY_ONE; } /* @return InstanceCookie node */ protected Class[] cookieClasses () { return new Class[] { InstanceCookie.class }; } /* Human presentable name of the action. This should be * presented as an item in a menu. * @return the name of the action */ public String getName () { return ActionConstants.BUNDLE.getString ("CustomizeBean"); } /* Help context where to find more about the acion. * @return the help context for this action */ public HelpCtx getHelpCtx () { return new HelpCtx (CustomizeBeanAction.class); } /* Resource name for the icon. * @return resource name */ protected String resourceIcon () { return "/org/openide/resources/actions/customize.gif"; // NOI18N } /** Customize a Bean. * @param cookie the object which can be instantiated */ public static void customize (final InstanceCookie cookie) { if (cookie == null) return; final ResourceBundle bundle = ActionConstants.BUNDLE; Window w = null; // Visual rep. of bean Object b = null; // BEAN try { b = cookie.instanceCreate (); } catch (Exception ex) { TopManager.getDefault ().notifyException (ex); return; } final Object bean = b; // show visual repres. of bean if (bean instanceof java.awt.Window) { w = (java.awt.Window)bean; w.addWindowListener (new java.awt.event.WindowAdapter () { public void windowClosing(java.awt.event.WindowEvent e) { e.getWindow ().dispose (); } }); } else if (bean instanceof java.awt.Component) { w = new PropertyDialogManager (//null, bundle.getString ("CTL_Component_Title"), (java.awt.Component)bean, false ).getDialog (); } final Window window = w; // create propertysheet PropertySheet propertySheet = new PropertySheet (); Node[] nodes = new Node [1]; BeanNode bn = null; try { bn = new BeanNode(bean); } catch (java.beans.IntrospectionException e) { TopManager.getDefault().notify( new NotifyDescriptor.Exception(e, bundle.getString("EXC_Introspection")) ); return; } nodes [0] = bn; propertySheet.setNodes (nodes); final JButton ser = new JButton (bundle.getString ("CTL_Serialize")); final JButton serAs = new JButton (bundle.getString ("CTL_SerializeAs")); final JButton cancel = new JButton (bundle.getString ("CTL_Cancel")); // dialog[0] = opened dialog final Dialog dialog[] = new Dialog[1]; boolean brr = java.io.Serializable.class.isAssignableFrom (bean.getClass ()); serAs.setEnabled (brr); ser.setEnabled (brr && cookie instanceof InstanceCookie.Origin); ActionListener listener = new ActionListener () { public void actionPerformed (ActionEvent ev) { if (ev.getSource () == cancel) { dialog[0].dispose (); if (window != null) window.dispose (); return; } if (serializeJavaBean (bean, ev.getSource () == serAs ? null : ((InstanceCookie.Origin)cookie).instanceOrigin () )) { dialog[0].dispose (); if (window != null) window.dispose (); } } }; DialogDescriptor descr = new DialogDescriptor ( propertySheet, java.text.MessageFormat.format (bundle.getString ("FMT_CTL_CustomizeTitle"), new Object[] { bean.getClass ().getName () }), false, // modal new Object[] { ser, serAs, cancel }, // options cancel, // initial value DialogDescriptor.DEFAULT_ALIGN, new HelpCtx (CustomizeBeanAction.class.getName () + ".dialog"), // NOI18N listener ); dialog[0] = TopManager.getDefault ().createDialog (descr); dialog[0].show (); if (window != null) { Rectangle r = dialog [0].getBounds (); window.setLocation (r.x + r.width, r.y); window.show (); } } /** Serialize a bean to file. * * @param bean the bean to be serialized * @param file the file to serialize to, or <code>null</code> to prompt the user for a destination * @return <code>true</code> if successful */ public static boolean serializeJavaBean (final Object bean, final FileObject file) { final ResourceBundle bundle = ActionConstants.BUNDLE; FileObject parent = null; String name = null; org.openide.filesystems.FileSystem targetFS; try { if (file == null) { TopManager tm = TopManager.getDefault (); JTextField tf = new JTextField (20); try { // selects one folder from data systems DataFolder df = (DataFolder)tm.getNodeOperation ().select ( bundle.getString ("CTL_SerializeAs"), bundle.getString ("CTL_SaveIn"), tm.getPlaces().nodes().repository(new FolderFilter()), new FolderAcceptor(), tf )[0].getCookie(DataFolder.class); parent = df.getPrimaryFile (); targetFS = parent.getFileSystem (); name = tf.getText (); } catch (org.openide.util.UserCancelException ex) { return false; } } else { parent = file.getParent (); name = file.getName (); targetFS = file.getFileSystem (); } } catch (org.openide.filesystems.FileStateInvalidException e) { TopManager.getDefault ().notify (new NotifyDescriptor.Exception (e, bundle.getString ("EXC_Serialization") + " " + name)); return false; } final String fileName = name; final FileObject parentFile = parent; try { targetFS.runAtomicAction(new org.openide.filesystems.FileSystem.AtomicAction() { public void run() throws IOException { ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; OutputStream os = null; FileObject serFile = null; FileLock lock = null; try { oos = new java.io.ObjectOutputStream (baos = new ByteArrayOutputStream ()); oos.writeObject (bean); if ((serFile = parentFile.getFileObject (fileName, "ser")) == null) // NOI18N serFile = parentFile.createData (fileName, "ser"); // NOI18N lock = serFile.lock (); oos.close (); baos.writeTo (os = serFile.getOutputStream (lock)); } finally { if (lock != null) lock.releaseLock (); if (os != null) os.close (); } } } ); } catch (Exception e) { TopManager.getDefault ().notify ( new NotifyDescriptor.Exception (e, bundle.getString ("EXC_Serialization") + " " + parent.getPackageName ('.') + '.' + name) ); return false; } return true; } /** Filter for save as operation, accepts folders. */ private static final class FolderFilter implements DataFilter { static final long serialVersionUID =6754682007992329276L; /** Accepts only data folders but ignore read only roots of file systems */ public boolean acceptDataObject (DataObject obj) { return obj instanceof DataFolder && (!obj.getPrimaryFile ().isReadOnly () || obj.getPrimaryFile ().getParent () != null); } } // end of FolderFilter inner class /** Node acceptor that accepts read-write folders only */ private static final class FolderAcceptor implements NodeAcceptor { public boolean acceptNodes (Node[] nodes) { if ((nodes == null) || (nodes.length == 0)) return false; DataFolder cookie = (DataFolder)nodes[0].getCookie (DataFolder.class); return nodes.length == 1 && cookie != null && !cookie.getPrimaryFile().isReadOnly(); } } // end of FolderAcceptor inner class } /* * Log * 23 Gandalf 1.22 1/12/00 Ian Formanek NOI18N * 22 Gandalf 1.21 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 21 Gandalf 1.20 8/9/99 Ian Formanek Generated Serial Version * UID * 20 Gandalf 1.19 8/4/99 Jan Jancura Bug 2335 * 19 Gandalf 1.18 7/26/99 Ian Formanek Fixed bug 2151 - * Customization of a Bean doesn't work * 18 Gandalf 1.17 7/25/99 Ian Formanek real class name * displayed in the title * 17 Gandalf 1.16 7/25/99 Ian Formanek Fixed bug #1908 - * BeanCustomizer doesn't show the name of bean it's editing. * 16 Gandalf 1.15 7/25/99 Ian Formanek Fixed bug 2333 - Could * not customize Bean and serialize. * 15 Gandalf 1.14 6/24/99 Jesse Glick Gosh-honest HelpID's. * 14 Gandalf 1.13 6/9/99 Ian Formanek Fixed resources for * package change * 13 Gandalf 1.12 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 12 Gandalf 1.11 5/28/99 Ian Formanek Cleaned up source * (imports, ... - no semantic/english text change) * 11 Gandalf 1.10 5/27/99 Jaroslav Tulach Executors rearanged. * 10 Gandalf 1.9 5/2/99 Ian Formanek Obsoleted * help->DEFAULT_HELP * 9 Gandalf 1.8 4/27/99 Jesse Glick new HelpCtx () -> * HelpCtx.DEFAULT_HELP. * 8 Gandalf 1.7 3/26/99 Jesse Glick [JavaDoc] * 7 Gandalf 1.6 3/20/99 Jaroslav Tulach DialogDescriptor has * only ActionListener * 6 Gandalf 1.5 2/17/99 Ian Formanek Updated icons to point * to the right package (under ide/resources) * 5 Gandalf 1.4 1/25/99 David Peroutka * 4 Gandalf 1.3 1/20/99 David Simonek rework of class DO * 3 Gandalf 1.2 1/7/99 Ian Formanek fixed resource names * 2 Gandalf 1.1 1/6/99 Jaroslav Tulach * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ */